package com.google.code.p.restrpc.client;

import java.util.Properties;

import org.apache.commons.lang.StringUtils;

import com.google.code.p.restrpc.DefaultServiceNode;
import com.google.code.p.restrpc.RpcOptions;
import com.google.code.p.restrpc.RpcProtocal;
import com.google.code.p.restrpc.RpcRequest;
import com.google.code.p.restrpc.ServiceNode;
import com.google.code.p.restrpc.TransferFormat;
import com.google.code.p.restrpc.UrlParser;
import com.google.code.p.restrpc.client.cluster.FailureRecovery;
import com.google.code.p.restrpc.client.loadbalance.LoadBalance;
import com.google.code.p.restrpc.core.url.DefaultUrlParser;

/**
 * restrpc.transfer.format restrpc.loadbalance.strategy
 * restrpc.failurerecovery.strategy restrpc.client.retries
 * restrpc.client.heartbeat restrpc.directory.service.url
 * restrpc.notify.service.url
 * 
 * @author dz
 */
public class DefaultRpcOptions implements RpcOptions {
    
    private UrlParser urlParser = new DefaultUrlParser();
    
    private TransferFormat transferFormat = TransferFormat.JSON;
    
    private LoadBalance loadBalance = LoadBalance.WeightedRoundRobin;
    
    private FailureRecovery failureRecovery = FailureRecovery.FailOver;
    
    private int numberOfRetries = 0;
    
    private String directoryServiceUrl;
    
    private int heartbeat = 60 * 1000;
    
    private ServiceNode[] serviceNodes = new ServiceNode[0];
    
    private RpcRequest[] rpcRequests = new RpcRequest[0];
    
    public DefaultRpcOptions() {
    }
    
    public DefaultRpcOptions(Properties properties) {
        if (properties != null) {
            initProperties(properties);
        }
    }
    
    private void initProperties(Properties properties) {
        LoadBalance loadBalanceStrategy = getDefaultLoadBalanceStrategy(properties);
        if (null != loadBalanceStrategy) {
            this.loadBalance = loadBalanceStrategy;
        }
        
        FailureRecovery failureRecovery = getDefaultFailureRecoveryStrategy(properties);
        if (null != failureRecovery) {
            this.failureRecovery = failureRecovery;
        }
        
        TransferFormat transferFormat = getTransferFormat(properties);
        if (null != transferFormat) {
            this.transferFormat = transferFormat;
        }
        
        int numberOfRetries = getNumberOfRetries(properties);
        if (-1 != numberOfRetries) {
            this.numberOfRetries = numberOfRetries;
        }
        
        int heartbeat = getHeartBeat(properties);
        if (-1 != heartbeat) {
            this.heartbeat = heartbeat;
        }
        
        this.directoryServiceUrl = getDirectoryServiceUrl(properties);
    }
    
    public static LoadBalance getDefaultLoadBalanceStrategy(Properties properties) {
        String loadBalanceStrategyName = properties.getProperty(RESTRPC_LOADBALANCE_STRATEGY);
        if (StringUtils.isEmpty(loadBalanceStrategyName)) {
            return null;
        }
        return LoadBalance.valueOf(loadBalanceStrategyName);
    }
    
    public static FailureRecovery getDefaultFailureRecoveryStrategy(Properties properties) {
        String failureRecoveryStrategyName = properties.getProperty(RESTRPC_FAILURERECOVERY_STRATEGY);
        if (StringUtils.isEmpty(failureRecoveryStrategyName)) {
            return null;
        }
        return FailureRecovery.valueOf(failureRecoveryStrategyName);
    }
    
    public static int getNumberOfRetries(Properties properties) {
        String retries = properties.getProperty(RESTRPC_CLIENT_RETRIES);
        if (StringUtils.isEmpty(retries)) {
            return -1;
        }
        return Integer.parseInt(retries);
    }
    
    public static int getHeartBeat(Properties properties) {
        String poolSize = properties.getProperty(RESTRPC_CLIENT_HEARTBEAT);
        if (StringUtils.isEmpty(poolSize)) {
            return -1;
        }
        return Integer.parseInt(poolSize);
    }
    
    public static TransferFormat getTransferFormat(Properties properties) {
        String transferFormat = properties.getProperty(RESTRPC_TRANSFER_FORMAT);
        if (StringUtils.isEmpty(transferFormat)) {
            return null;
        }
        return TransferFormat.valueOf(transferFormat);
    }
    
    public static String getDirectoryServiceUrl(Properties properties) {
        return properties.getProperty(RESTRPC_DIRECTORY_SERVICE_URL);
    }
    
    protected void setUrlParser(UrlParser urlParser) {
        this.urlParser = urlParser;
    }
    
    protected void setLoadBalance(LoadBalance defaultLoadBalanceStrategy) {
        if (null == defaultLoadBalanceStrategy) {
            throw new IllegalArgumentException("defaultLoadBalanceStrategy can't be null!");
        }
        this.loadBalance = defaultLoadBalanceStrategy;
    }
    
    protected void setFailureRecovery(FailureRecovery defaultFailureRecoveryStrategy) {
        if (null == defaultFailureRecoveryStrategy) {
            throw new IllegalArgumentException("defaultFailureRecoveryStrategy can't be null!");
        }
        this.failureRecovery = defaultFailureRecoveryStrategy;
    }
    
    protected void setNumberOfRetries(int numberOfRetries) {
        this.numberOfRetries = numberOfRetries;
    }
    
    protected void setHeartbeat(int heartbeat) {
        this.heartbeat = heartbeat;
    }
    
    protected void setServiceRegistryUrl(String directoryServiceUrl) {
        if (StringUtils.isEmpty(directoryServiceUrl)) {
            throw new IllegalArgumentException("directoryServiceUrl can't be null or empty!");
        }
        this.directoryServiceUrl = directoryServiceUrl;
    }
    
    /**
     * @return the urlParser
     */
    public UrlParser getUrlParser() {
        return urlParser;
    }
    
    /**
     * @return the transferFormat
     */
    public TransferFormat getTransferFormat() {
        return transferFormat;
    }
    
    /**
     * @return the loadBalance
     */
    public LoadBalance getLoadBalance() {
        return loadBalance;
    }
    
    /**
     * @return the failureRecovery
     */
    public FailureRecovery getFailureRecovery() {
        return failureRecovery;
    }
    
    /**
     * @return the numberOfRetries
     */
    public int getNumberOfRetries() {
        return numberOfRetries;
    }
    
    /**
     * @return the directoryServiceUrl
     */
    public String getDirectoryServiceUrl() {
        return directoryServiceUrl;
    }
    
    /**
     * @return the heartbeat
     */
    public int getHeartbeat() {
        return heartbeat;
    }
    
    public ServiceNode[] getServiceNodes() {
        return serviceNodes;
    }
    
    public RpcRequest[] getRpcRequests() {
        return rpcRequests;
    }
    
    public static void main(String[] args) {
        ServiceNode[] destinations = new DefaultServiceNode().parse("192.168.0.119:80,192.168.0.200:8080");
        for (int i = 0; i < destinations.length; i++) {
            System.out.println(destinations[i].getAddress());
            System.out.println(destinations[i].getPort());
            System.out.println("**************************");
        }
        
        destinations = new DefaultServiceNode().parse("192.168.0.119:80");
        for (int i = 0; i < destinations.length; i++) {
            System.out.println(destinations[i].getAddress());
            System.out.println(destinations[i].getPort());
            System.out.println("**************************");
        }
        
        System.out.flush();
        
        destinations = new DefaultServiceNode().parse("");
    }
    
}
